﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace JsEditor
{
    public abstract class WinFormGame : IDisposable, IServiceProvider, IGraphicsDeviceService 
    {

        public PresentationParameters parameters = new PresentationParameters();
        public GraphicsDevice graphicsDevice;
        public SpriteBatch spriteBatch;
        public ContentManager Content;
        public Color ClearColor;
        public int Width, Height;
        public bool Enabled=true, Visible=true;
        Dictionary<Type, object> services = new Dictionary<Type, object>();
        Stopwatch stopWatch = new Stopwatch();
        Control drawControl;

        public void AddService<T>(T service)
        {
            services.Add(typeof(T), service);
        }

        public object GetService(Type serviceType)
        {
            object service;
            services.TryGetValue(serviceType, out service);
            return service;
        }

        public GraphicsDevice GraphicsDevice
        {
            get { return graphicsDevice; }
        }

        public WinFormGame()
        {

            parameters.BackBufferWidth = 800;
            parameters.BackBufferHeight = 600;
            parameters.BackBufferFormat = SurfaceFormat.Color;
            parameters.DepthStencilFormat = DepthFormat.None;
            parameters.PresentationInterval = PresentInterval.Default;
            parameters.MultiSampleCount = 0;
            parameters.IsFullScreen = false;
        }


        public void InitGraphicsDevice(Control control)
        {
            drawControl = control;
            drawControl.Resize += new EventHandler(OnResize);
            drawControl.Disposed+= new EventHandler(OnDestroy);
            Width = drawControl.Width;
            Height = drawControl.Height;
            ClearColor.R = drawControl.BackColor.R;
            ClearColor.G = drawControl.BackColor.G;
            ClearColor.B = drawControl.BackColor.B;
            ClearColor.A = drawControl.BackColor.A;
            
            parameters.DeviceWindowHandle = drawControl.Handle;
            parameters.BackBufferWidth = Width;
            parameters.BackBufferHeight = Height;


            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
                                                GraphicsProfile.HiDef,
                                                parameters);
            AddService<IGraphicsDeviceService>(this);

            if (DeviceCreated != null)
                DeviceCreated(this,EventArgs.Empty);

            Content = new ContentManager(this, "Content");
            spriteBatch = new SpriteBatch(graphicsDevice);

            Init();
        }

        public void Dispose()
        {
            Deinit();

            if (DeviceDisposing != null)
                DeviceDisposing(this, EventArgs.Empty);
            graphicsDevice.Dispose();
        }

        public virtual void OnResize(Object sender,EventArgs e)
        {
            Width = drawControl.Width;
            Height = drawControl.Height;
            ResetDevice(Width, Height);
        }

        public virtual void OnUpdate(Object sender, EventArgs e)
        {

            int dtime = (int)stopWatch.ElapsedMilliseconds;
            stopWatch.Reset();
            stopWatch.Start();
            if(Enabled)
                Update(dtime);
            if(Visible)
                OnDraw();
        }


        public virtual void OnDestroy(Object sender,EventArgs e)
        {
            Dispose();
        }

        void ResetDevice(int width, int height)
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);

            parameters.BackBufferWidth = Width = width;
            parameters.BackBufferHeight = Height = height;

            graphicsDevice.Reset(parameters);

            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }

        bool CheckDeviceStatus()
        {
            if (graphicsDevice.GraphicsDeviceStatus == GraphicsDeviceStatus.Lost)
                return false;
            if (graphicsDevice.GraphicsDeviceStatus == GraphicsDeviceStatus.NotReset)
            {
                graphicsDevice.Reset(parameters);
                return false;
            }
            return true;
        }


        public virtual void OnDraw()
        {
            if(Visible)
             if (CheckDeviceStatus())
            {
                graphicsDevice.Clear(ClearColor);
                Draw();
                graphicsDevice.Present();
            }
        }


        public abstract void Update(int dtime);
        public abstract void Draw();
        public abstract void Init();
        public abstract void Deinit();

        public event EventHandler<EventArgs> DeviceCreated;
        public event EventHandler<EventArgs> DeviceDisposing;
        public event EventHandler<EventArgs> DeviceReset;
        public event EventHandler<EventArgs> DeviceResetting;


    }
}
